//	Name: map.js 
//	Description:  Draws US map by default with polygon lines for the states. Also draws county lines
// 				for the five "red" states. Displays state names when hovered over with the mouse when 
// 				viewing the United States, and displays county names when hovered over with the mouse when viewing
//              a state.
//	Revision History:
//  11/15/2011 Chris Lewis: Commented code for Alpha Release
//  10/13/2011 Chris Lewis: Commented the code and put final polish on the file
//  10/13/2011 Chris Lewis: Implemented mouseover functionality on county names
//  10/12/2011 Chris Lewis: Added comment header
//	10/10/2011 Chris Lewis: Incorporated state data and county data to draw polygons on the map
//	9/2011 tlc: Initial version.


// This is a global variable for the infoWindow which is displayed when a county/state is moused over. This is 
// a global variable so that only one InfoWindow is ever displayed at one time.
// The content and position of the infoWindow will be changed by the function which eventually ends up
// making the infoWindow.
var infowindow = new google.maps.InfoWindow({
	content: "to be updated"
}); 

// Global variables for the shading of states and counties
var red = "#FF0019";
var blue = "#7592D3";

// - update()
// This function redraws the map depending on selections made by the user
function update(){
	// Get the current selections of the dropdown menus for a state and category of data
	var chooseState = document.getElementById("chooseState");
	var options = chooseState.options;
	var selected = options[chooseState.selectedIndex].text
	
	var chooseCategory = document.getElementById("chooseCategory");
	var categoryOptions = chooseCategory.options;
	var selectedCategory = categoryOptions[chooseCategory.selectedIndex].text
	// Depending on the selection, focus the map on a certain area and draw certain polygons
	if(selected == "Washington")
	{
		// Create the center coordinate to center the map on and construct the Washington county borders
		var washingtonLatLng = new google.maps.LatLng(47.3917, -121.5708);
		var washingtonCountyBorders = constructWashingtonCounties();
		
		// Pass the name of the selection, the two constructed variables, and the zoom level to the drawCounties function
		drawCounties(selected, washingtonLatLng, 6, washingtonCountyBorders, selectedCategory);
	}
	else if(selected == "Illinois")
	{
		// Create the center coordinate to center the map on and construct the Illinois county borders
		var illinoisLatLng = new google.maps.LatLng(40.08, -89.184);
		var illinoisCountyBorders = constructIllinoisCounties();
		
		// Pass the name of the selection, the two constructed variables, and the zoom level to the drawCounties function
		drawCounties(selected, illinoisLatLng, 6, illinoisCountyBorders, selectedCategory);
	}
	else if(selected == "Oregon")
	{
		// Create the center coordinate to center the map on and construct the Oregon county borders
		var oregonLatLng = new google.maps.LatLng(44, -120.587);
		var oregonCountyBorders = constructOregonCounties(); 	
		// Pass the name of the selection, the two constructed variables, and the zoom level to the drawCounties function	
		drawCounties(selected, oregonLatLng, 6, oregonCountyBorders, selectedCategory);
	}
	else if(selected == "Hawaii")
	{
		// Create the center coordinate to center the map on and construct the Hawaii county borders
		var hawaiiLatLng = new google.maps.LatLng(21.18, -157.51); 
		var hawaiiCountyBorders = constructHawaiiCounties();
		// Pass the name of the selection, the two constructed variables, and the zoom level to the drawCounties function
		drawCounties(selected, hawaiiLatLng, 6, hawaiiCountyBorders, selectedCategory);
	}
	else if(selected == "California")
	{
		// Create the center coordinate to center the map on and construct the California county borders
		var californiaLatLng = new google.maps.LatLng(36.579, -120.49); 
		var californiaCountyBorders = constructCaliforniaCounties();	
		// Pass the name of the selection, the two constructed variables, and the zoom level to the drawCounties function
		drawCounties(selected, californiaLatLng, 5, californiaCountyBorders, selectedCategory);
	}
	else if(selected == "United States")
	{
		// Draw the map of the United States
		drawStates(selectedCategory);
	}
}

// -initialize()
// This function is called when the application is initially opened, and draws the United States filtered on the
// Number Inquired category
function initialize()
{
	drawStates("Number Inquired");
}

// -drawCounties
// drawCounties will redraw the map, focusing on a state with county outlines.
// Parameters:
// 	@name: the name of the state being focused on
// 	@latLng: the latitude and longitude to center the map on
// 	@mapZoom: the zoom level of the map
// 	@borders: The coordinates of the county lines of the state
//  @selected: The category of data being focused on
function drawCounties(name, latLng, mapZoom, borders, selected)
{
	// Update the direct state-to-state/county-to-county comparison select menus and barcharts
	updateComparisonSelections(name);
	// Create the options for the map
    var options = {
        zoom: mapZoom,
        center: latLng,
        mapTypeId: google.maps.MapTypeId.ROADMAP
    };
    
    // Draw the map using the options defined above.
    var map = new google.maps.Map(document.getElementById("usmap_canvas"),
    options);
    
    // Open the county data that gives the number of inquiries for each county in the state
    d3.csv(name + "CountyData.csv", function(data) {
		// The five largest counties will be shaded red. In order to determine these, we use an array
		// to store the six largest numbers seen in the data. 
		// Each time we pass through the data, if the smallest element in the array is smaller than the 
		// contents of the data field being passed over, the smallest element is replaced with the data.
		// The array is sorted each pass through the data in order to determine the smallest element of the 
		// array.
		
		var sixLargest = [0, 0, 0, 0, 0, 0];
    	data.forEach(function(d)
    	{
    		// Count up the number of inquiries for the current county for the years selected
    		var number = incrementNumber(selected, d);
			// replace the smallest element of the array
			if(number > sixLargest[0])
				sixLargest[0] = number;	
			// sort the array, using the sortNumber function defined in this file.
			sixLargest.sort(sortNumber);
    	});
    	// Get the largest and smallest elements out of the array in order to do comparisons for shading
    	// of counties
    	var largest = sixLargest[5];
    	var smallest = sixLargest[0];
    	data.forEach(function(d)
    	{
    		// Count up the number of inquiries for the current county
    		var number = incrementNumber(selected, d);
    		// Create a display string to put in the InfoWindow for this county
    		// when it's hovered over
    		var contentString = "<p><b>"+d.county+" County</b><br>"+
			   		selected +": "+number+"<br></p>";

			// Depending on whether the number of inquiries is greater than the smallest element
			// of the array, the county will be shaded red or blue. If it is greater, the county
			// will be shaded red. Otherwise, it will be shaded blue.
			
			// The max shade will be the value that determines the maximum opacity of shading for a county.
			// The greater the number of inquiries, the darker it will be shaded.
			var maxShade = 0;
			if(number > smallest)
			{
				color = red;
				maxShade = largest;
			}			
			else
			{
				color = blue;
				maxShade = smallest;
			}
			var opacity = 0.3 + 0.4 * number/maxShade;
			
			// Make the county polygon
			countyName = d.county;
			// These are special cases, where the counties have multiple polygons
			if(countyName=="Kauai"||countyName=="Maui"||countyName=="Ventura"||countyName=="Santa Barbara"||countyName=="Los Angeles")
			{
				// There are three polygons for these states, so we iterate through a loop to make them all
				for(i = 0; i<3; i++)
				{
			    	county = new google.maps.Polygon({
				     	    paths: borders[countyName+i],
					        strokeColor: color,
					        strokeOpacity: 0.9,
					        strokeWeight: 1,
					        fillColor: color,
					        fillOpacity: opacity
				   		 }); 
				    // Make the mouse-over listener for displaying an InfoWindow 
					google.maps.event.addListener(county,"mouseover",function(event){ 
				   		infowindow.setContent(contentString);
						infowindow.setPosition(event.latLng);
						infowindow.open(map);
					}); 
					// Add a listener so that if a user mouses out of a county, the infowindow disappears.
				   	google.maps.event.addListener(county,"mouseout",function(event){ 
				   		infowindow.close(map);
					}); 
					// Draw the county polygon on the map
			   		county.setMap(map);
		   		}
		   	}
		   	// This is a special case, where the county has two polygons
		   	else if(countyName=="San Francisco")
		   	{
		   		// Iterate through the polygons
				for(i = 0; i<2; i++)
				{
			    	county = new google.maps.Polygon({
				     	    paths: borders[countyName+i],
					        strokeColor: color,
					        strokeOpacity: 0.9,
					        strokeWeight: 1,
					        fillColor: color,
					        fillOpacity: opacity
				   		 });
			   		// Make the mouse-over listener for displaying an InfoWindow 
					google.maps.event.addListener(county,"mouseover",function(event){ 
				   		infowindow.setContent(contentString);
						infowindow.setPosition(event.latLng);
						infowindow.open(map);
					}); 
					// Add a listener so that if a user mouses out of a county, the infowindow disappears.
				   	google.maps.event.addListener(county,"mouseout",function(event){ 
				   		infowindow.close(map);
					}); 
					// Draw the county polygon on the map
			   		county.setMap(map);
		   		}
		   	}
		   	// All these counties only have one polygon
		   	else
		   	{
		   		county = new google.maps.Polygon({
			     	    paths: borders[d.county],
				        strokeColor: color,
				        strokeOpacity: 0.9,
				        strokeWeight: 1,
				        fillColor: color,
				        fillOpacity: opacity
			   		 }); 
			    // Make the mouse-over listener for displaying an InfoWindow
				google.maps.event.addListener(county,"mouseover",function(event){ 
			   		infowindow.setContent(contentString);
					infowindow.setPosition(event.latLng);
					infowindow.open(map);
				}); 
				// Add a listener so that if a user mouses out of a county, the infowindow disappears.
			   	google.maps.event.addListener(county,"mouseout",function(event){ 
			   		infowindow.close(map);
				}); 
				// Draw the county polygon on the map
		   		county.setMap(map);
		   	}
	  	});
	 });
}

// -sortNumber(a,b)
// This function is used by the sorting function to sort the array in ascending order.
function sortNumber(a,b)
{
	return a - b;
}

// -incrementNumber(selected, d)
// This function uses the data passed to it to return the number of inquired, applied, accepted, or enrolled
// Parameters:
//  @selected: inquired, applied, accepted, or enrolled
//  @d: a record from a csv file
// Return:
//  The incremented number
function incrementNumber(selected, d)
{
	// Get the values of the checkboxes on the html page in order to know which data to read
	var checked2007 = document.getElementById("2007").checked;
	var checked2008 = document.getElementById("2008").checked;
	var checked2009 = document.getElementById("2009").checked;
	var checked2010 = document.getElementById("2010").checked;
	//initialize the number to return
	var number = 0;
	if(selected=="Number Inquired")
	{
  		if(checked2007)
			number = number + parseInt(d.inquired2007);
		if(checked2008)
			number = number + parseInt(d.inquired2008);
		if(checked2009)
			number = number + parseInt(d.inquired2009);
		if(checked2010)
			number = number + parseInt(d.inquired2010);
	}
	else if(selected=="Number Applied")
	{
  		if(checked2007)
			number = number + parseInt(d.applied2007);
		if(checked2008)
			number = number + parseInt(d.applied2008);
		if(checked2009)
			number = number + parseInt(d.applied2009);
		if(checked2010)
			number = number + parseInt(d.applied2010);
	}
	else if(selected=="Number Accepted")
	{
  		if(checked2007)
			number = number + parseInt(d.accepted2007);
		if(checked2008)
			number = number + parseInt(d.accepted2008);
		if(checked2009)
			number = number + parseInt(d.accepted2009);
		if(checked2010)
			number = number + parseInt(d.accepted2010);
	}
	else if(selected=="Number Enrolled")
	{
  		if(checked2007)
			number = number + parseInt(d.enrolled2007);
		if(checked2008)
			number = number + parseInt(d.enrolled2008);
		if(checked2009)
			number = number + parseInt(d.enrolled2009);
		if(checked2010)
			number = number + parseInt(d.enrolled2010);
	}
	return number;
}

// - drawStates(selected)
// This function is called upon opening of the webpage. By default, it draws the US map, with inquiry data for 2009.
// This function is also called when a user selects the United States view or is in the United States view and changes
// a checkbox. 
// Parameters:
//	@selected: the state (or "United States") selected by the user
function drawStates(selected){
	// Update the drop-down menus for the state-to-state / county-to-county comparison
	updateComparisonSelections("United States");
	
    // Create a new Google map of the United States
    var usLatLng = new google.maps.LatLng(44, -115);
	
    // Initialize the US map options
    var usOptions = {
        zoom: 3,
        center: usLatLng,
        mapTypeId: google.maps.MapTypeId.ROADMAP
    };
           
    // Draw the map using the options defined above.
    var usMap = new google.maps.Map(document.getElementById("usmap_canvas"),
        usOptions);
        
    // Get the coordinates for the state borders
    var stateBorders = constructStateLines();
    
    // Open a csv which holds the state data for inquiries, applied, accepted, enrolled
    d3.csv("StatesData.csv", function(data) {
    	// The application shades the 5 main states (OR WA IL HI CA) red, and shades the
    	// rest of the states blue. We iterate through the csv to determining the maximum
    	// number of inquiries from the "blue" states and the maximum from the "red" states 
    	// in order to determine a maximum on the shading scale for these states.
    	// The states with the most inquiries will be shaded more darkly
    	var maxRedShade = 0;
    	var maxBlueShade = 0;
    	// Iterate through the data and determine the max shading for blue and red states
    	data.forEach(function(d)
    	{
    		// Determine the number of the selected category for this state
      		var number = incrementNumber(selected, d);
    		name = d.abbrev;
    		if((maxRedShade < number) && (name == "OR" || name == "WA" || name == "IL" || name =="HI" || name == "CA"))
    		{
    			maxRedShade = number;
    		}
    		if((maxBlueShade < number) && name != "OR" && name != "WA" && name != "IL" && name !="HI" && name != "CA")
    		{
    			maxBlueShade = number;
    		}
    	});
    	// Now that we have the maximum shadings, go through the data and draw and shade the polygons appropriately
    	data.forEach(function(d)
    	{
    		// Determine the number of the selected category for this state
			var number = incrementNumber(selected, d);
			// Make a string to display in an info window for this state
			var contentString = "<p><b>"+d.state+"</b><br>"+
			   		selected +": "+number+"<br></p>";
			// Shade these states red. Note: HI is a special case with multiple polygons
    		if(d.abbrev == "OR" || d.abbrev == "WA" || d.abbrev == "IL" || d.abbrev == "CA")
    		{
    			// Draw and shade the polygon and put it on the map
	    		var opacity = 0.10 + 0.40 * number/maxRedShade;
	  			stateArea = new google.maps.Polygon({
		     	    paths: stateBorders[d.abbrev],
			        strokeColor: red,
			        strokeOpacity: 0.1,
			        strokeWeight: 1,
			        fillColor: red,
			        fillOpacity: opacity
	   			 }); 
	   			 // Add the mouse over listener to display an info window
			   	google.maps.event.addListener(stateArea,"mouseover",function(event){ 
			   		infowindow.setContent(contentString);
					infowindow.setPosition(event.latLng);
					infowindow.open(usMap);
				}); 
				// Add a listener so that if a user mouses out of a county, the infowindow disappears.
			   	google.maps.event.addListener(stateArea,"mouseout",function(event){ 
			   		infowindow.close(usMap);
				}); 
	   		  	 stateArea.setMap(usMap);
    		}
    		else if(d.abbrev == "HI")
    		{
    			// Draw and shade the polygons and put them on the map
    			var opacity = 0.10 + 0.40 * number/maxRedShade;
    			// Iterate through the 8 polygons for Hawaii, drawing and shading each
    			for(i = 0; i < 8; i++)
    			{
    				// Draw and shade the polygon and put it on the map
    				stateArea = new google.maps.Polygon({
		     	    	paths: stateBorders[d.abbrev+i],
				        strokeColor: red,
				        strokeOpacity: 0.1,
				        strokeWeight: 1,
				        fillColor: red,
				        fillOpacity: opacity
		   			 }); 
		   			 // Add the mouse over listener to display an info window
		   			google.maps.event.addListener(stateArea,"mouseover",function(event){ 
				   		infowindow.setContent(contentString);
						infowindow.setPosition(event.latLng);
						infowindow.open(usMap);
					}); 
					// Add a listener so that if a user mouses out of a county, the infowindow disappears.
				   	google.maps.event.addListener(stateArea,"mouseout",function(event){ 
				   		infowindow.close(usMap);
					}); 
	    			stateArea.setMap(usMap);
    			}
    			
    		}
    		// AK is a special case of a blue state with multiple polygons
    		else if(d.abbrev == "AK")
    		{
    			// Iterate through the 19 polygons for Alaska, drawing and shading each
    			var opacity = 0.10 + 0.40 * number/maxBlueShade;
	    		for(i = 0; i < 19; i++)
	    		{
	    			// Draw and shade the polygon and put it on the map
		  			stateArea = new google.maps.Polygon({
			     	    paths: stateBorders[d.abbrev+i],
				        strokeColor: blue,
				        strokeOpacity: 0.1,
				        strokeWeight: 1,
				        fillColor: blue,
				        fillOpacity: opacity
		   		 	}); 
		   		 	// Add the mouse over listener to display an info window
					google.maps.event.addListener(stateArea,"mouseover",function(event){ 
				   		infowindow.setContent(contentString);
						infowindow.setPosition(event.latLng);
						infowindow.open(usMap);
					}); 
				// Add a listener so that if a user mouses out of a county, the infowindow disappears.
				   	google.maps.event.addListener(stateArea,"mouseout",function(event){ 
				   		infowindow.close(usMap);
					}); 		   		 	
		   		  	stateArea.setMap(usMap);
		   		 }
	    	}
		    else
		    {
		    	//Draw and shade the polygon and put it on the map
	    		var opacity = 0.10 + 0.40 * number/maxBlueShade;
		  		stateArea = new google.maps.Polygon({
		     	    paths: stateBorders[d.abbrev],
			        strokeColor: blue,
			        strokeOpacity: 0.1,
			        strokeWeight: 1,
			        fillColor: blue,
			        fillOpacity: opacity
		   		 }); 
		   		 // Add the mouse over listener to display an info window
				 google.maps.event.addListener(stateArea,"mouseover",function(event){ 
			   		infowindow.setContent(contentString);
					infowindow.setPosition(event.latLng);
					infowindow.open(usMap);
				 }); 
				 // Add a listener so that if a user mouses out of a county, the infowindow disappears.
			   	 google.maps.event.addListener(stateArea,"mouseout",function(event){ 
			   		infowindow.close(usMap);
				 }); 
		   		 stateArea.setMap(usMap);
		    }
    	});
    });
}